﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Windows.Media.Imaging;
using System.Text;
using System.Device.Location;
using first_learn.GeocodeService;
using System.Xml.Linq;

using System.IO;
using System.Text;
using System.Windows;
using SocketEx;

namespace PicHub
{
    public class Picture : IComparable
    {
        private BitmapImage source;
        private int id;
        private int popularity;
        private int time;
        private string city;
        private double priority;

        public Picture(BitmapImage img, string info)
        {
            this.source = img;
            this.id = Convert.ToInt32(info);
        }

        public BitmapImage getBitmapImage()
        {
            return source;
        }
        public double getPriority()
        {
            return priority;
        }
        public int getId()
        {
            return id;
        }

        public void setPriority()
        {
            priority = System.Math.Pow(time, 1.5) + System.Math.Sqrt(popularity);
        }
        public int CompareTo(object obj)
        {
            if (obj == null) return 1;

            Picture that = obj as Picture;
            if (that != null)
            {
                if (this.getPriority() > that.getPriority())
                    return 1;
                else if (this.getPriority() == that.getPriority())
                    return 0;
                else
                    return -1;
            }
            else
            {
                throw new ArgumentException("Compare failed!");
            }
        }

    }

    public partial class MainPage : PhoneApplicationPage
    {
        private GeoCoordinateWatcher watcher;
        private double latitude = 0;
        private double longitude = 0;
        private string This_address = "";

        private int rowCounter = 0;

        private const string serverAddress = "sslab13.cs.purdue.edu";
        private const int serverPort = 4546;

        string[] country;
        string[] state;

        // Constructor
        public MainPage()
        {
            StartLocationService(GeoPositionAccuracy.Default);
            //onConnect();
            InitializeComponent();

            var connection = CreateConnection();
            var stream = connection.GetStream();

            var reader = new StreamReader(stream);
            var writer = new StreamWriter(stream);
            var request = "GETIMAGEID NEW" + " West_Lafayette,IN 8"; 

            writer.WriteLine(request);
            writer.Flush();

            var fullMessage = new StringBuilder();

            string message;
            while ((message = reader.ReadLine()) != null)
            {
                if (string.IsNullOrWhiteSpace(message))
                    break;

                fullMessage.AppendLine(message);
            }

            string result = "";
            if(fullMessage.Length>2) 
                result = fullMessage.ToString().Substring(0, fullMessage.Length-2);
            string[] wjw = result.Split(' ');
            int num = Convert.ToInt32(wjw[0]);
            string[] idList = wjw[1].Split('#');

            //Console.WriteLine("result: " + result);
            //Console.WriteLine("idList[0]: " + idList[0]);

            BitmapImage[] test = new BitmapImage[8];
            for (int i = 0; i < 8; i++)
            {
                if (i >= num) i=i%num;
                test[i] = new BitmapImage(new Uri("http://sslab13.cs.purdue.edu:4546/" + idList[i]));
            }

            List<Picture> newList = new List<Picture>();
            for (int i = 0; i < 8; i++)
            {
                Picture tmp = new Picture(test[i], i.ToString());
                newList.Add(tmp);
            }
            //set8Images(newList);
            for (int i = 0; i < 3; i++)
                set8Images(newList, idList);
           
        }

        private TcpClient CreateConnection()
        {
            var connection = new TcpClient(serverAddress, serverPort);

            return connection;
        }

        #region loadimages
      /*  private void UseClientClick(object sender, RoutedEventArgs e)
        {
            var connection = CreateConnection();
            var stream = connection.GetStream();

            var reader = new StreamReader(stream);
            var writer = new StreamWriter(stream);
            var request = "INFO COMMENT 1";

            writer.WriteLine(request);
            writer.Flush();

            var fullMessage = new StringBuilder();

            string message;
            while ((message = reader.ReadLine()) != null)
            {
                if (string.IsNullOrWhiteSpace(message))
                    break;

                fullMessage.AppendLine(message);
            }

            Content.Text = fullMessage.ToString();
        }

        private TcpClient CreateConnection()
        {
            var connection = new TcpClient(serverAddress, serverPort);

            return connection;
        }
        */
        #endregion


        private void image_tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            if (e.OriginalSource is Image)
            {
                Image touchImage = (Image)e.OriginalSource;
                string touchId = touchImage.Name;
                NavigationService.Navigate(new Uri("/ViewPage.xaml?value=" + touchId, UriKind.Relative));
                //NavigationService.Navigate(new Uri("/ViewPage.xaml?id=3", UriKind.Relative));
            }
        }


        private void sort8Images(List<Picture> args)
        {
            args.Sort();
        }

        private void set8Images(List<Picture> args, String[] idList)
        {
            // sort8Images(args);

            // initial image list.
            Image[] img = new Image[8];
            for (int i = 0; i < 8; i++)
            {
                img[i] = new Image();
                img[i].Source = args[i].getBitmapImage();
                img[i].Name = idList[i];
                img[i].Tap += image_tap;
            }
            // initial stack panel list.
            StackPanel[] sp = new StackPanel[3];
            for (int i = 0; i < 3; i++)
            {
                sp[i] = new StackPanel();
                sp[i].Margin = new Thickness(12, 0, 12, 10);
            }

            // Set images.
            // image 1;
            img[0].Width = 456;
            // image 2;
            img[1].Width = 224;
            img[1].Margin = new Thickness(0, 0, 5, 0);
            // image 3;
            img[2].Width = 224;
            img[2].Margin = new Thickness(5, 0, 0, 0);
            // image 4;
            img[3].Width = 224;
            img[3].Margin = new Thickness(0, 0, 5, 0);
            // image 5;
            img[4].Width = 108;
            img[4].Margin = new Thickness(0, 0, 5, 5);
            // image 6;
            img[5].Width = 108;
            img[5].Margin = new Thickness(0, 5, 5, 0);
            // image 7;
            img[6].Width = 108;
            img[6].Margin = new Thickness(5, 0, 0, 5);
            // image 8;
            img[7].Width = 108;
            img[7].Margin = new Thickness(5, 5, 0, 0);

            // stack panel has one image.
            sp[0].Children.Add(img[0]);

            // stack panel has two images.
            Grid sp2Grid = new Grid();
            ColumnDefinition[] columnForSp2 = new ColumnDefinition[2];
            for (int i = 0; i < 2; i++)
            {
                columnForSp2[i] = new ColumnDefinition();
                columnForSp2[i].Width = new GridLength(229);
                sp2Grid.ColumnDefinitions.Add(columnForSp2[i]);
            }
            for (int i = 0; i < 2; i++)
            {
                Grid.SetColumn(img[1 + i], i);
                sp2Grid.Children.Add(img[1 + i]);
            }
            sp[1].Children.Add(sp2Grid);

            // stack pandel has three images.
            Grid sp3Grid = new Grid();
            ColumnDefinition[] columnForSp3 = new ColumnDefinition[2];
            for (int i = 0; i < 2; i++)
            {
                columnForSp3[i] = new ColumnDefinition();
                columnForSp3[i].Width = new GridLength(229);
                sp3Grid.ColumnDefinitions.Add(columnForSp3[i]);
            }
            Grid FourGrid = new Grid();
            FourGrid.Margin = new Thickness(5, 0, 0, 0);
            ColumnDefinition[] FourColumn = new ColumnDefinition[2];
            RowDefinition[] FourRow = new RowDefinition[2];
            for (int i = 0; i < 2; i++)
            {
                FourColumn[i] = new ColumnDefinition();
                FourColumn[i].Width = new GridLength(113);
                FourGrid.ColumnDefinitions.Add(FourColumn[i]);
                FourRow[i] = new RowDefinition();
                if (i == 0)
                {
                    FourRow[i].Height = new GridLength(0, GridUnitType.Auto);
                }
                else
                {
                    FourRow[i].Height = new GridLength(0, GridUnitType.Star);
                }
                FourGrid.RowDefinitions.Add(FourRow[i]);
            }
            for (int i = 0; i < 3; i = i + 2)
            {
                Grid.SetColumn(img[4 + i], i);
                Grid.SetColumn(img[5 + i], i);
                Grid.SetRow(img[4 + i], 0);
                Grid.SetRow(img[5 + i], 1);
                FourGrid.Children.Add(img[4 + i]);
                FourGrid.Children.Add(img[5 + i]);
            }
            Grid.SetColumn(img[3], 0);
            Grid.SetColumn(FourGrid, 1);
            sp3Grid.Children.Add(img[3]);
            sp3Grid.Children.Add(FourGrid);
            sp[2].Children.Add(sp3Grid);

            // if it is loading latest images;
            /*
             this.Content.Children.Clear();
             rowCounter = 0;
             _imageList.Clear();
             */

            // if not;
            // add Row Definition.
            RowDefinition[] row = new RowDefinition[3];
            for (int i = 0; i < 3; i++)
            {
                row[i] = new RowDefinition();
                this.Content.RowDefinitions.Add(row[i]);
                if (rowCounter == 0)
                {
                    row[i].Height = new GridLength(0, GridUnitType.Auto);
                }
                else
                {
                    row[i].Height = new GridLength(0, GridUnitType.Auto);
                }
                ++rowCounter;
            }

            // random display;
            Random rand = new Random();
            int num1 = rand.Next(3);
            int num2;
            int num3;
            for (num2 = rand.Next(3); num2 == num1; num2 = rand.Next(3)) ;
            for (num3 = rand.Next(3); num3 == num1 || num3 == num2; num3 = rand.Next(3)) ;

            Grid.SetRow(sp[num1], rowCounter - 3);
            this.Content.Children.Add(sp[num1]);
            Grid.SetRow(sp[num2], rowCounter - 2);
            this.Content.Children.Add(sp[num2]);
            Grid.SetRow(sp[num3], rowCounter - 1);
            this.Content.Children.Add(sp[num3]);
        }


        public static Guid GetId()
        {
            Guid applicationId = Guid.Empty;

            var productId = XDocument.Load("WMAppManifest.xml").Root.Element("App").Attribute("ProductID");

            if (productId != null && !string.IsNullOrEmpty(productId.Value))
                Guid.TryParse(productId.Value, out applicationId);

            return applicationId;
        }

        #region Application logic


        /// <summary>
        /// Helper method to start up the location data acquisition
        /// </summary>
        /// <param name="accuracy">The accuracy level </param>
        private void StartLocationService(GeoPositionAccuracy accuracy)
        {
            // Reinitialize the GeoCoordinateWatcher
            watcher = new GeoCoordinateWatcher(accuracy);
            watcher.MovementThreshold = 20;

            // Add event handlers for StatusChanged and PositionChanged events
            watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
            watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);

            // Start data acquisition
            watcher.Start();
        }

        /// <summary>
        /// Handler for the StatusChanged event. This invokes MyStatusChanged on the UI thread and
        /// passes the GeoPositionStatusChangedEventArgs
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MyStatusChanged(e));
        }
        /// <summary>
        /// Custom method called from the StatusChanged event handler
        /// </summary>
        /// <param name="e"></param>
        void MyStatusChanged(GeoPositionStatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case GeoPositionStatus.Disabled:
                    // The location service is disabled or unsupported.
                    // Alert the user
                    //StatusTextBlock.Text = "location is unsupported on this device";
                    break;
                case GeoPositionStatus.Initializing:
                    // The location service is initializing.
                    // Disable the Start Location button
                    //StatusTextBlock.Text = "initializing location service," + accuracyText;
                    break;
                case GeoPositionStatus.NoData:
                    // The location service is working, but it cannot get location data
                    // Alert the user and enable the Stop Location button
                    //StatusTextBlock.Text = "data unavailable," + accuracyText;
                    break;
                case GeoPositionStatus.Ready:
                    // The location service is working and is receiving location data
                    // Show the current position and enable the Stop Location button
                    //StatusTextBlock.Text = "receiving data, " + accuracyText;
                    break;

            }
        }

        /// <summary>
        /// Handler for the PositionChanged event. This invokes MyStatusChanged on the UI thread and
        /// passes the GeoPositionStatusChangedEventArgs
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MyPositionChanged(e));
        }

        /// <summary>
        /// Custom method called from the PositionChanged event handler
        /// </summary>
        /// <param name="e"></param>
        void MyPositionChanged(GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            // Update the TextBlocks to show the current location
            //textBox1.Text = e.Position.Location.Latitude.ToString("0.000");
            //textBox2.Text = e.Position.Location.Longitude.ToString("0.000");
            latitude = e.Position.Location.Latitude;
            longitude = e.Position.Location.Longitude;
            GeocodeServiceClient client = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");

            client.ReverseGeocodeCompleted += new EventHandler<ReverseGeocodeCompletedEventArgs>(OnReverseGeocodeCompleted);

            ReverseGeocodeRequest request = new ReverseGeocodeRequest();
            request.Credentials = new Credentials();
            request.Credentials.ApplicationId = "AjjGZGtCVs7lEuRn860kGigumg5hhJ8LqKXOIxpk1zwuxxQUgcrFDRWmrYfYCtFg";
            Location loc = new Location();
            loc.Latitude = e.Position.Location.Latitude;
            loc.Longitude = e.Position.Location.Longitude;
            request.Location = loc;
            client.ReverseGeocodeAsync(request);
        }

        private void OnReverseGeocodeCompleted(object sender, ReverseGeocodeCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                if (e.Result.Results.Count >= 0)
                {
                    GeocodeResponse response = e.Result;

                    //textBox3.Text = response.Results[0].DisplayName;
                    This_address = response.Results[0].DisplayName;
                    country = This_address.Split(',');
                  state = country[2].Split(' ');
                    PageTitle.Text = country[1] + ", " + state[1];
                    //System.Collections.ObjectModel.ObservableCollection<GeocodeResult> list = response.Results;
                    //string allName = "";
                    //foreach (GeocodeResult i in list)
                    //{
                    //    allName += i.DisplayName + "  ";
                    //}
                    //textBox3.Text = allName;
                }
                else
                    MessageBox.Show("Sorry, cannot find location!");
            }
        }

        #endregion

        void Camera(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/MainPageFive.xaml", UriKind.Relative));
        }

        void Location(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/MainPageThree.xaml", UriKind.Relative));
        }

        void Refresh(object sender, EventArgs e)
        {
            //UpdateImage();
            NavigationService.Navigate(new Uri("/MainPageSix.xaml", UriKind.Relative));
        }

        private void menuItem3_Click(object sender, System.EventArgs e)
        {
            // exit 
            throw new Exception("exit");
        }
    }
}